package com.hm.service.utils;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.SecureRandom;
import java.util.Base64;
import java.util.HexFormat;

/**
 * AES/CBC/PKCS5Padding又称AES-256加解密模式和算法
 * 增加了随机且唯一的偏移量，安全性大大提升，注意点：密码派生秘钥长度256，偏移量32字节长度
 */
public class CBC_Encryption {

    private static final String ALGORITHM = "AES";
    private static final String TRANSFORMATION = "AES/CBC/PKCS5Padding";
    private static final int IV_LENGTH_BYTES = 16; // AES块大小固定16字节
    private static final int KEY_LENGTH_BYTES = 32; // AES-256需要32字节密钥
    private static final SecureRandom secureRandom = new SecureRandom();

    public static String encrypt(String plaintext, String key) {
        try {
            if (key == null || key.length() != KEY_LENGTH_BYTES * 2) {
                throw new IllegalArgumentException("密钥必须是 32 字节（64字符Hex）");
            }
            byte[] sKey = HexFormat.of().parseHex(key);//转为十六进制字符串->字节数组

            byte[] iv = new byte[IV_LENGTH_BYTES];//生成随机IV字节数组（16字节）
            secureRandom.nextBytes(iv);
            IvParameterSpec ivParameterSpec = new IvParameterSpec(iv);
            String sIv = HexFormat.of().formatHex(iv);//格式化-字节数组->十六进制字符串

            Cipher cipher = Cipher.getInstance(TRANSFORMATION);//算法加密
            cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(sKey, ALGORITHM), ivParameterSpec);

            //密文base64->对应crypto-js加密后就是base64格式
            byte[] ciphertext = cipher.doFinal(plaintext.getBytes(StandardCharsets.UTF_8));
            String ciphertextBase64 = Base64.getEncoder().encodeToString(ciphertext);

            return sIv + ciphertextBase64; //偏移量+密文
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public static String decrypt(String plaintext, String key) {
        try {
            if (key == null || key.length() != KEY_LENGTH_BYTES * 2) {
                throw new IllegalArgumentException("密钥必须是 32 字节（64字符Hex）");
            }
            byte[] sKey = HexFormat.of().parseHex(key);//格式化

            String iv = plaintext.substring(0, 32);//提取偏移量
            byte[] sIV = HexFormat.of().parseHex(iv);//格式化
            IvParameterSpec ivParameterSpec = new IvParameterSpec(sIV);//偏移量

            String ciphertextBase64 = plaintext.substring(32);//提取密文
            byte[] decode = Base64.getDecoder().decode(ciphertextBase64);//解码

            Cipher cipher = Cipher.getInstance(TRANSFORMATION);//算法解密
            cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(sKey, ALGORITHM), ivParameterSpec);

            byte[] bytes = cipher.doFinal(decode);
            return new String(bytes, StandardCharsets.UTF_8);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}
